package example

import (
	"context"
	"encoding/json"
	"fmt"
	"github.com/360EntSecGroup-Skylar/excelize"
	"github.com/tencentyun/cos-go-sdk-v5"
	"google.golang.org/grpc/status"
	"io"
	"log"
	"mime/multipart"
	"net/http"
	"net/url"
	"qm_system_server/server/proto/grpc/config"
	"strconv"
	"strings"

	"qm_system_server/server/model/example"

	"github.com/gin-gonic/gin"
	"go.uber.org/zap"
	"qm_system_server/server/global"
	"qm_system_server/server/model/common/response"
	exampleRes "qm_system_server/server/model/example/response"
	"qm_system_server/server/utils"
)

// BreakpointContinue
// @Tags      ExaFileUploadAndDownload
// @Summary   断点续传到服务器
// @Security  ApiKeyAuth
// @accept    multipart/form-data
// @Produce   application/json
// @Param     file  formData  file                           true  "an example for breakpoint resume, 断点续传示例"
// @Success   200   {object}  response.Response{msg=string}  "断点续传到服务器"
// @Router    /fileUploadAndDownload/breakpointContinue [post]
func (b *FileUploadAndDownloadApi) BreakpointContinue(c *gin.Context) {
	fileMd5 := c.Request.FormValue("fileMd5")
	fileName := c.Request.FormValue("fileName")
	//chunkMd5 := c.Request.FormValue("chunkMd5")

	chunkNumber, _ := strconv.Atoi(c.Request.FormValue("chunkNumber"))
	chunkTotal, _ := strconv.Atoi(c.Request.FormValue("chunkTotal"))
	_, FileHeader, err := c.Request.FormFile("file")
	if err != nil {
		global.GVA_LOG.Error("接收文件失败!", zap.Error(err))
		response.FailWithMessage("接收文件失败", c)
		return
	}
	f, err := FileHeader.Open()
	if err != nil {
		global.GVA_LOG.Error("文件读取失败!", zap.Error(err))
		response.FailWithMessage("文件读取失败", c)
		return
	}
	defer func(f multipart.File) {
		err := f.Close()
		if err != nil {
			fmt.Println(err)
		}
	}(f)
	cen, _ := io.ReadAll(f)
	//if !utils.CheckMd5(cen, chunkMd5) {
	//	global.GVA_LOG.Error("检查md5失败!", zap.Error(err))
	//	response.FailWithMessage("检查md5失败", c)
	//	return
	//}
	file, err := fileUploadAndDownloadService.FindOrCreateFile(fileMd5, fileName, chunkTotal)
	if err != nil {
		global.GVA_LOG.Error("查找或创建记录失败!", zap.Error(err))
		response.FailWithMessage("查找或创建记录失败", c)
		return
	}
	pathC, err := utils.BreakPointContinue(cen, fileName, chunkNumber, chunkTotal, fileMd5)
	if err != nil {
		global.GVA_LOG.Error("断点续传失败!", zap.Error(err))
		response.FailWithMessage("断点续传失败", c)
		return
	}

	if err = fileUploadAndDownloadService.CreateFileChunk(file.ID, pathC, chunkNumber); err != nil {
		global.GVA_LOG.Error("创建文件记录失败!", zap.Error(err))
		response.FailWithMessage("创建文件记录失败", c)
		return
	}
	response.OkWithMessage("切片创建成功", c)
}

// FindFile
// @Tags      ExaFileUploadAndDownload
// @Summary   查找文件
// @Security  ApiKeyAuth
// @accept    multipart/form-data
// @Produce   application/json
// @Param     file  formData  file                                                        true  "Find the file, 查找文件"
// @Success   200   {object}  response.Response{data=exampleRes.FileResponse,msg=string}  "查找文件,返回包括文件详情"
// @Router    /fileUploadAndDownload/findFile [post]
func (b *FileUploadAndDownloadApi) FindFile(c *gin.Context) {
	fileMd5 := c.Query("fileMd5")
	fileName := c.Query("fileName")
	chunkTotal, _ := strconv.Atoi(c.Query("chunkTotal"))
	file, err := fileUploadAndDownloadService.FindOrCreateFile(fileMd5, fileName, chunkTotal)
	if err != nil {
		global.GVA_LOG.Error("查找失败!", zap.Error(err))
		response.FailWithMessage("查找失败", c)
	} else {
		response.OkWithDetailed(exampleRes.FileResponse{File: file}, "查找成功", c)
	}
}

// BreakpointContinueFinish
// @Tags      ExaFileUploadAndDownload
// @Summary   创建文件
// @Security  ApiKeyAuth
// @accept    multipart/form-data
// @Produce   application/json
// @Param     file  formData  file                                                            true  "上传文件完成"
// @Success   200   {object}  response.Response{data=exampleRes.FilePathResponse,msg=string}  "创建文件,返回包括文件路径"
// @Router    /fileUploadAndDownload/findFile [post]
func (b *FileUploadAndDownloadApi) BreakpointContinueFinish(c *gin.Context) {
	fileMd5 := c.Query("fileMd5")
	fileName := c.Query("fileName")
	configId := c.Query("configId")

	filePath, err := utils.MakeFile(fileName, fileMd5)
	if err != nil {
		global.GVA_LOG.Error("文件创建失败!", zap.Error(err))
		response.FailWithDetailed(exampleRes.FilePathResponse{FilePath: filePath}, "文件创建失败", c)
	} else {
		//读取excel 并解析成数组
		file, err := excelize.OpenFile(filePath)
		if err != nil {
			fmt.Println(err)
			return
		}
		sheetList := file.GetSheetMap()
		fmt.Println(sheetList)

		// 读取指定的工作表
		sheetName := file.GetSheetName(1)

		rows := file.GetRows(sheetName)
		//判断rows是否为空
		if len(rows) == 0 {
			response.FailWithMessage("Excel表为空", c)
			return
		}

		// 定义一个切片来存储 JSON 格式的数据
		var jsonData []map[string]interface{}

		// 获取 Excel 表头
		headers := rows[1]

		for i, row := range rows {
			// 跳过表头行
			if i == 0 || i == 1 {
				continue
			}

			// 定义一个 map 来存储当前行的数据
			data := make(map[string]interface{})

			// 将当前行的数据存储到 map 中
			for j, cell := range row {
				data[headers[j]] = cell
			}

			// 将当前行的数据添加到 JSON 数据中
			jsonData = append(jsonData, data)
		}

		// 将 JSON 格式的数据打印到控制台
		jsonBytes, err := json.MarshalIndent(jsonData, "", "  ")
		if err != nil {
			log.Fatal(err)
		}

		baseUrl := "https://" + global.GVA_CONFIG.TencentCOS.Bucket + ".cos." + global.GVA_CONFIG.TencentCOS.Region + ".myqcloud.com"

		u, _ := url.Parse(baseUrl)
		b := &cos.BaseURL{BucketURL: u}
		cosClient := cos.NewClient(b, &http.Client{
			Transport: &cos.AuthorizationTransport{
				SecretID:  global.GVA_CONFIG.TencentCOS.SecretID,  // 用户的 SecretId，建议使用子账号密钥，授权遵循最小权限指引，降低使用风险。子账号密钥获取可参考 https://cloud.tencent.com/document/product/598/37140
				SecretKey: global.GVA_CONFIG.TencentCOS.SecretKey, // 用户的 SecretKey，建议使用子账号密钥，授权遵循最小权限指引，降低使用风险。子账号密钥获取可参考 https://cloud.tencent.com/document/product/598/37140
			},
		})

		gameHash := c.Request.Header.Get("game-hash")
		platformId := c.Request.Header.Get("platform-id")

		path := global.GVA_CONFIG.TencentCOS.PathPrefix + "/" + gameHash + "/" + fileMd5 + "-" + platformId + ".json"

		_, err = cosClient.Object.Put(context.Background(), path, strings.NewReader(string(jsonBytes)), nil)
		if err != nil {
			panic(err)
		}

		url := global.GVA_CONFIG.TencentCOS.BaseURL + path

		//ourl := cosClient.Object.GetObjectURL(path)

		//grpc 储存
		client := config.NewConfigServiceClient(global.ServerGrpc)
		//string转成int64
		configIdInt, _ := strconv.ParseInt(configId, 10, 64)

		_, err = client.Update(context.Background(), &config.UpdateRequest{
			Config: &config.Config{
				Id:  configIdInt,
				Url: url,
			},
		})

		if err != nil {
			st, ok := status.FromError(err)
			if ok {
				// 获取 gRPC 错误的描述信息
				response.FailWithMessage(st.Message(), c)
			}
			return
		}

		response.OkWithDetailed(exampleRes.FilePathResponse{FilePath: filePath}, "文件创建成功", c)
	}
}

// RemoveChunk
// @Tags      ExaFileUploadAndDownload
// @Summary   删除切片
// @Security  ApiKeyAuth
// @accept    multipart/form-data
// @Produce   application/json
// @Param     file  formData  file                           true  "删除缓存切片"
// @Success   200   {object}  response.Response{msg=string}  "删除切片"
// @Router    /fileUploadAndDownload/removeChunk [post]
func (b *FileUploadAndDownloadApi) RemoveChunk(c *gin.Context) {
	var file example.ExaFile
	err := c.ShouldBindJSON(&file)
	if err != nil {
		response.FailWithMessage(err.Error(), c)
		return
	}
	err = utils.RemoveChunk(file.FileMd5)
	if err != nil {
		global.GVA_LOG.Error("缓存切片删除失败!", zap.Error(err))
		return
	}
	err = fileUploadAndDownloadService.DeleteFileChunk(file.FileMd5, file.FilePath)
	if err != nil {
		global.GVA_LOG.Error(err.Error(), zap.Error(err))
		response.FailWithMessage(err.Error(), c)
		return
	}
	response.OkWithMessage("缓存切片删除成功", c)
}
